#include "Device.h"
#include "const.h"
#include "MyException.h"
#include <syslog.h>


Device::Device(Comunicador * c, Comunicador * cn, ColaBloqueante<Device*> &q):
							comunicador(c), comunicadorNotif(cn), colaTareas(q) {
	desconec = false;
}

Device::~Device(){
	comunicador->cerrarComunicacion();
	comunicadorNotif->cerrarComunicacion();
}

// Ejecuta el loop principal del device: espera que el cliente se comunique
// con los cambios en la copia local del mismo, y envia notificaciones sobre cambios en
// otros devices del mismo user.
void Device::run() {
	try {
		while(running){

			// Recibe el siguiente mensaje del cliente.
			std::string mensajeRecibido;
			if (comunicador->recibirMensaje(mensajeRecibido) == 0){
				// Se desconecto el cliente (o se cerro la comunicacion
				// del lado server para cerrarse).
				desconectarDelServer();
				break;
			}

			// Encola el comando para ser ejecutado por el usuario, y setea los parametros
			// necesarios.
			size_t pos = mensajeRecibido.find_first_of(' ');
			std::string aux, params;
			aux = mensajeRecibido.substr(0,pos);
			if (pos != std::string::npos) params = mensajeRecibido.substr(pos+1);

			comandos[aux]->parametros(params);
			cola.push(comandos[aux]);
			colaTareas.push(this);

			// Envia una respuesta al cliente.
			std::string respuesta = colaRespuestas.pop();
			if (respuesta == SINRESPUESTA) continue;
			if ((respuesta.substr(0, respuesta.find_first_of(" "))) == NOTIFY) respuesta = LOGINOK;
			if (comunicador->enviarMensaje(respuesta) == 0){
				// Se desconecto el cliente (o se cerro la comunicacion
				// del lado server para cerrarse).
				desconectarDelServer();
				break;
			}
		}
	} catch(std::exception & e){
		std::cout << e.what() << std::endl;
		syslog(LOG_ERR, "El programa se ha cerrado inesperadamente: %s ", e.what());
	}
}

void Device::desconectarDelServer(){
	desconec = true;
	colaTareas.push(this);
}

bool Device::esperandoDesconexion(){
	return desconec;
}

// Agrega una notificacion a ser enviada al finalizar de procesar la proxima
// tarea.
void Device::notificar(std::string msj){
	int pos = msj.find_first_of(" ");
	std::string notif = msj.substr(pos + 1);
	comunicadorNotif->enviarMensaje(notif);
	comunicadorNotif->recibirMensaje(notif);
}

// Cierra la conexion con el cliente.
void Device::stop(){
	this->running = false;
	comunicador->cerrarComunicacion();
}

// Ejecuta la siguiente tarea pendiente.
std::string Device::ejecutarTarea(std::string nombre){
	std::string buff = cola.pop()->execute(nombre);
	colaRespuestas.push(buff);
	return buff;
}

int Device::compare(Device &device){
	if (this->comunicador != device.comunicador) return -1;
	else return 0;
}
